{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Anaconda\\lib\\site-packages\\h5py\\__init__.py:34: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n"
     ]
    }
   ],
   "source": [
    "# 0 各种import\n",
    "import numpy as np\n",
    "import h5py\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "plt.rcParams['figure.figsize'] = (5.0, 4.0) # 设定图片的默认尺寸\n",
    "plt.rcParams['image.interpolation'] = 'nearest'\n",
    "plt.rcParams['image.cmap'] = 'gray'\n",
    "%load_ext autoreload\n",
    "%autoreload 2\n",
    "np.random.seed(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 定义要用到的方法\n",
    "def sigmoid(Z):\n",
    "    \"\"\"\n",
    "    使用numpy实现sigmoid函数\n",
    "    Arguments:\n",
    "    Z -- 任何尺寸的numpy array\n",
    "    Returns:\n",
    "    A -- 输出sigmoid(z), 形状和Z一样\n",
    "    cache -- 就是Z，在反向传播中会用到\n",
    "    \"\"\"\n",
    "    A = 1/(1+np.exp(-Z))\n",
    "    cache = Z\n",
    "    return A, cache\n",
    "\n",
    "\n",
    "def relu(Z):\n",
    "    \"\"\"\n",
    "    使用numpy实现relu函数\n",
    "    Arguments:\n",
    "    Z -- 任何尺寸的numpy array\n",
    "    Returns:\n",
    "    A -- 输出relu(z), 形状和Z一样\n",
    "    cache -- 就是Z，在反向传播中会用到\n",
    "    \"\"\"\n",
    "    A = np.maximum(0,Z)\n",
    "    assert(A.shape == Z.shape)\n",
    "    cache = Z \n",
    "    return A, cache\n",
    "\n",
    "\n",
    "def relu_backward(dA, cache):\n",
    "    \"\"\"\n",
    "    实现了relu单元的反向传播\n",
    "    Arguments:\n",
    "    dA -- 激活函数的梯度\n",
    "    cache -- 之前定义的relu函数中的返回值，前向传播之前的Z\n",
    "    Returns:\n",
    "    dZ -- 损失函数对Z的梯度\n",
    "    \"\"\"\n",
    "    Z = cache\n",
    "    dZ = np.array(dA, copy=True) # relu导数为1(输入大于0)，所以直接直接复制一份dA即可\n",
    "    dZ[Z <= 0] = 0 # 当输入小于0时，relu导数为0，所以dZ中小于0的数变为0\n",
    "    assert (dZ.shape == Z.shape)\n",
    "    return dZ\n",
    "\n",
    "\n",
    "def sigmoid_backward(dA, cache):\n",
    "    \"\"\"\n",
    "     实现了sigmoid单元的反向传播\n",
    "    Arguments:\n",
    "    dA -- 激活函数的梯度\n",
    "    cache -- 之前定义的sigmoid函数中的返回值，前向传播之前的Z\n",
    "    Returns:\n",
    "    dZ -- 损失函数对Z的梯度\n",
    "    \"\"\"\n",
    "    Z = cache\n",
    "    s = 1/(1+np.exp(-Z))\n",
    "    dZ = dA * s * (1-s) # dA乘sigmoid导数\n",
    "    assert (dZ.shape == Z.shape)\n",
    "    return dZ\n",
    "\n",
    "\n",
    "def load_data():\n",
    "    \"\"\"\n",
    "    读取数据\n",
    "    \"\"\"\n",
    "    train_dataset = h5py.File('datasets/train_catvnoncat.h5', \"r\")\n",
    "    train_set_x_orig = np.array(train_dataset[\"train_set_x\"]) # 训练样本 shape:(209, 64, 64, 3)\n",
    "    train_set_y_orig = np.array(train_dataset[\"train_set_y\"]) # 训练样本标签 shape:(1, 209)\n",
    "    \n",
    "    test_dataset = h5py.File('datasets/test_catvnoncat.h5', \"r\")\n",
    "    test_set_x_orig = np.array(test_dataset[\"test_set_x\"]) # 测试样本 shape:(50, 64, 64, 3)\n",
    "    test_set_y_orig = np.array(test_dataset[\"test_set_y\"]) # 测试样本标签 shape:(1, 50)\n",
    "    \n",
    "    classes = np.array(test_dataset[\"list_classes\"][:]) # 标签类别(一共两类：是猫、不是猫)\n",
    "    \n",
    "    train_set_y_orig = train_set_y_orig.reshape((1, -1)) # 确保标签是一行数据 下同\n",
    "    test_set_y_orig = test_set_y_orig.reshape((1, -1))\n",
    "    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "训练集样本数量: 209\n",
      "测试集样本数量: 50\n",
      "每个图片的尺寸(最后的3是RGB三色通道): (64, 64, 3)\n",
      "train_x_orig shape: (209, 64, 64, 3)\n",
      "train_y shape: (1, 209)\n",
      "test_x_orig shape: (50, 64, 64, 3)\n",
      "test_y shape: (1, 50)\n"
     ]
    }
   ],
   "source": [
    "# 把数据弄下来\n",
    "train_x_orig, train_y, test_x_orig, test_y, classes = load_data()\n",
    "\n",
    "# 瞅一瞅你的数据\n",
    "m_train = train_x_orig.shape[0]\n",
    "num_px = train_x_orig.shape[1]\n",
    "m_test = test_x_orig.shape[0]\n",
    "print (\"训练集样本数量: \" + str(m_train))\n",
    "print (\"测试集样本数量: \" + str(m_test))\n",
    "print (\"每个图片的尺寸(最后的3是RGB三色通道): (\" + str(num_px) + \", \" + str(num_px) + \", 3)\")\n",
    "print (\"train_x_orig shape: \" + str(train_x_orig.shape))\n",
    "print (\"train_y shape: \" + str(train_y.shape))\n",
    "print (\"test_x_orig shape: \" + str(test_x_orig.shape))\n",
    "print (\"test_y shape: \" + str(test_y.shape))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train_x shape: (12288, 209)\n",
      "test_x shape: (12288, 50)\n"
     ]
    }
   ],
   "source": [
    "# 改变训练集和测试集的shape\n",
    "train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T\n",
    "test_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T\n",
    "\n",
    "# 标准化数据，使其值为0到1之间\n",
    "train_x = train_x_flatten/255.\n",
    "test_x = test_x_flatten/255.\n",
    "print (\"train_x shape: \" + str(train_x.shape))\n",
    "print (\"test_x shape: \" + str(test_x.shape))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 给定神经网络的层数和每层的节点数\n",
    "layers_dims = [12288, 20, 7, 5, 1] #  5-layer model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 1 初始化权重\n",
    "def initialize_parameters_deep(layer_dims):\n",
    "    \"\"\"\n",
    "    Arguments:\n",
    "    layer_dims -- 数组或集合，表示每一层的节点数量。\n",
    "    Returns:\n",
    "    parameters --  字典，包含\"W1\", \"b1\", ..., \"WL\", \"bL\":\n",
    "                    Wl -- 权重矩阵，其shape为 (layer_dims[l], layer_dims[l-1])\n",
    "                    bl -- 变差向量，其shape为 (layer_dims[l], 1)                    \n",
    "    \"\"\"\n",
    "    np.random.seed(3)\n",
    "    parameters = {}\n",
    "    L = len(layer_dims) # 网络层数\n",
    "    for l in range(1, L):\n",
    "        parameters['W' + str(l)] = np.random.randn(layer_dims[l] ,layer_dims[l-1]) / np.sqrt(layer_dims[l-1])#  *0.01 \n",
    "        parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))\n",
    "        assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l-1]))\n",
    "        assert(parameters['b' + str(l)].shape == (layer_dims[l], 1))\n",
    "    return parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 2.1 前向传播的线性部分\n",
    "def linear_forward(A, W, b):\n",
    "    \"\"\"\n",
    "    实现一层的前向传播的线性部分。\n",
    "    Arguments:\n",
    "    A -- 前一层的激活值(或者输入的数据)，其shape为(前一层的节点数, 样本数)\n",
    "    W -- 权重矩阵，其shape为(当前层的节点数，前一层的节点数)\n",
    "    b -- 偏差向量，其shape为(当前层的节点数，样本数)\n",
    "    Returns:\n",
    "    Z -- 激活函数的输入值\n",
    "    cache -- 字典，包含\"A\", \"W\", \"b\"; 存储这些值以供后向传播使用。\n",
    "    \"\"\"\n",
    "    Z = np.dot(W, A) + b\n",
    "    assert(Z.shape == (W.shape[0], A.shape[1]))\n",
    "    cache = (A, W, b)\n",
    "    return Z, cache"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 2.2 前向传播的线性激活部分\n",
    "def linear_activation_forward(A_prev, W, b, activation):\n",
    "    \"\"\"\n",
    "    实现前向传播的线性-激活部分\n",
    "    Arguments:\n",
    "    A_prev -- 前一层的激活值(或输入数据)，其shape为(前一层的节点数，样本数)\n",
    "    W -- 权重矩阵，其shape为(当前层的节点数，前一层的节点数)\n",
    "    b -- 偏差向量，其shape为(当前层的节点数，样本数)\n",
    "    activation -- 在这一层要用的激活函数，是字符串格式：\"sigmoid\" 或者 \"relu\" 等\n",
    "    Returns:\n",
    "    A -- 激活函数的输出值\n",
    "    cache -- 字典，包含\"linear_cache\" 和 \"activation_cache\"; 存储这些值以供后向传播使用。\n",
    "            \"linear_cache\"是linear_forward方法的返回值，包含\"A\", \"W\", \"b\"\n",
    "            \"activation_cache\"是本方法的返回值，其值为激活函数(\"sigmoid\" 或者 \"relu\" 等)\n",
    "    \"\"\"\n",
    "    if activation == \"sigmoid\":\n",
    "        # 输入: \"A_prev, W, b\". 输出: \"A, activation_cache\".\n",
    "        Z, linear_cache = linear_forward(A_prev, W, b)\n",
    "        A, activation_cache = sigmoid(Z)\n",
    "    elif activation == \"relu\":\n",
    "        # 输入: \"A_prev, W, b\". 输出: \"A, activation_cache\".\n",
    "        Z, linear_cache = linear_forward(A_prev, W, b)\n",
    "        A, activation_cache = relu(Z)\n",
    "    assert (A.shape == (W.shape[0], A_prev.shape[1]))\n",
    "    cache = (linear_cache, activation_cache)\n",
    "    return A, cache"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 2.3 前向传播\n",
    "def L_model_forward(X, parameters):\n",
    "    \"\"\"\n",
    "    实现前向传播\n",
    "    Arguments:\n",
    "    X -- 数据，其shape为(输入数据size，样本数)\n",
    "    parameters -- initialize_parameters_deep()方法输出的值，\n",
    "                    字典，包含\"W1\", \"b1\", ..., \"WL\", \"bL\":\n",
    "    Returns:\n",
    "    AL -- 最后的激活函数输出值\n",
    "    caches -- 包含: 每一个linear_relu_forward()的cache (有L-1个, 索引从 0 到 L-2)\n",
    "                   linear_sigmoid_forward()的cache (只有1个, 索引为 L-1)\n",
    "    \"\"\"\n",
    "    caches = []\n",
    "    A = X\n",
    "    L = len(parameters) // 2  # 神经网络的层数\n",
    "    # 实现(L-1)次线性-rulu，并将cache添加到caches中\n",
    "    for l in range(1, L):\n",
    "        A_prev = A \n",
    "        A, cache = linear_activation_forward(A_prev, parameters[\"W\"+str(l)], parameters[\"b\"+str(l)], activation = \"relu\")\n",
    "        caches.append(cache)\n",
    "    # 实现最后的这一次 线性-sigmoid，并将cache添加到caches中 （这里的sigmoid作用是将结果转换到0~1之间，输出作为概率）\n",
    "    AL, cache = linear_activation_forward(A, parameters[\"W\"+str(L)], parameters[\"b\"+str(L)], activation = \"sigmoid\")\n",
    "    caches.append(cache)\n",
    "    assert(AL.shape == (1,X.shape[1]))\n",
    "    return AL, caches"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 3 代价函数的计算\n",
    "def compute_cost(AL, Y):\n",
    "    \"\"\"\n",
    "    计算上面的代价函数\n",
    "    Arguments:\n",
    "    AL -- 是一个向量，每个值代表该样本的几率，shape为(1，样本数)\n",
    "    Y -- 真实值向量，shape为(1，样本数)\n",
    "    Returns:\n",
    "    cost -- 交叉熵\n",
    "    \"\"\"\n",
    "    m = Y.shape[1]\n",
    "    #  用AL和y计算cost\n",
    "    cost = -1/m * np.sum(Y*np.log(AL) + (1-Y)*np.log(1-AL))\n",
    "    cost = np.squeeze(cost) # 确保cost的shape是你想要的 (会把比如 [[17]] 变成 17).\n",
    "    assert(cost.shape == ())\n",
    "    return cost"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 4.1 后向传播的线性部分\n",
    "def linear_backward(dZ, cache):\n",
    "    \"\"\"\n",
    "    实现一层的后向传播的线性部分\n",
    "    Arguments:\n",
    "    dZ --当前层的线性导数(导数全是cost的导数)\n",
    "    cache -- 元组(A_prev, W, b)，由前向传播过程的当前层得来\n",
    "    Returns:\n",
    "    dA_prev -- 前一层的激活函数的导数，其shape和A_prev一样\n",
    "    dW -- 当前层 W 的导数，其shape和 W 一样\n",
    "    db -- 当前层 b 的导数，其shape和 b 一样\n",
    "    \"\"\"\n",
    "    A_prev, W, b = cache\n",
    "    m = A_prev.shape[1]\n",
    "    dW = 1/m * np.dot(dZ, A_prev.T)\n",
    "    db = 1/m * np.sum(dZ, axis = 1, keepdims = True)\n",
    "    dA_prev = np.dot(W.T, dZ)\n",
    "    assert (dA_prev.shape == A_prev.shape)\n",
    "    assert (dW.shape == W.shape)\n",
    "    assert (db.shape == b.shape)\n",
    "    return dA_prev, dW, db"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 4.2 后向传播的线性激活部分  \n",
    "def linear_activation_backward(dA, cache, activation):\n",
    "    \"\"\"\n",
    "    实现一层的后向传播的线性和激活函数部分\n",
    "    Arguments:\n",
    "    dA -- 当前层激活函数的导数\n",
    "    cache -- 元组：(linear_cache, activation_cache)，前向传播时存的\n",
    "    activation -- 这层要用的激活函数，string值: \"sigmoid\" 或者 \"relu\"\n",
    "    Returns:\n",
    "    dA_prev -- 前一层的激活函数的导数，其shape和A_prev一样\n",
    "    dW -- 当前层 W 的导数，其shape和 W 一样\n",
    "    db -- 当前层 b 的导数，其shape和 b 一样\n",
    "    \"\"\"\n",
    "    linear_cache, activation_cache = cache\n",
    "    if activation == \"relu\":\n",
    "        dZ = relu_backward(dA, activation_cache)\n",
    "        dA_prev, dW, db = linear_backward(dZ, linear_cache)\n",
    "    elif activation == \"sigmoid\":\n",
    "        dZ = sigmoid_backward(dA, activation_cache)\n",
    "        dA_prev, dW, db = linear_backward(dZ, linear_cache)\n",
    "    return dA_prev, dW, db"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 4.3 后向传播\n",
    "def L_model_backward(AL, Y, caches):\n",
    "    \"\"\"\n",
    "    实现后向传播： (L-1) 次 [LINEAR->RELU] 和 1 次 LINEAR->SIGMOID\n",
    "    Arguments:\n",
    "    AL -- 是一个向量，每个值代表该样本的几率，(来自L_model_forward())\n",
    "    Y -- 真实值向量(不是猫 0 , 是猫 1 )\n",
    "    caches -- 包含:\n",
    "                前向传播时存下来的数据：caches[0 ~ L-2]是relu部分 caches[L-1]是sigmoid部分\n",
    "                caches[l]具体包括：[线性cache[A, W, b],激活cache[Z]]\n",
    "    Returns:\n",
    "    grads -- 一个用来存储导数的字典：\n",
    "             grads[\"dA\" + str(l)] = ...\n",
    "             grads[\"dW\" + str(l)] = ...\n",
    "             grads[\"db\" + str(l)] = ...\n",
    "    \"\"\"\n",
    "    grads = {}\n",
    "    L = len(caches) # 神经网络的层数\n",
    "    m = AL.shape[1]\n",
    "    Y = Y.reshape(AL.shape) # 这行之后，Y 的shape就和 AL 一样了\n",
    "    \n",
    "    # 初始化后向传播，该值为损失函数对预测值AL求导的结果(Y是真实值)\n",
    "    dAL =  - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL)) \n",
    "    \n",
    "    # 第L层 (SIGMOID -> LINEAR) 的导数. \n",
    "    # 输入: \"AL, Y, caches\". \n",
    "    # 输出: \"grads[\"dAL\"], grads[\"dWL\"], grads[\"dbL\"]\n",
    "    current_cache = caches[L-1]\n",
    "    grads[\"dA\" + str(L)], grads[\"dW\" + str(L)], grads[\"db\" + str(L)] =  linear_activation_backward(dAL, current_cache, activation = \"sigmoid\")\n",
    "    for l in reversed(range(L - 1)):\n",
    "        # 第l层: (RELU -> LINEAR) 的导数.\n",
    "        # 输入: \"grads[\"dA\" + str(l + 2)], caches\". \n",
    "        # 输出: \"grads[\"dA\" + str(l + 1)] , grads[\"dW\" + str(l + 1)] , grads[\"db\" + str(l + 1)] \n",
    "        current_cache = caches[l]\n",
    "        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads[\"dA\" + str(l + 2)], current_cache, activation = \"relu\")\n",
    "        grads[\"dA\" + str(l + 1)] = dA_prev_temp\n",
    "        grads[\"dW\" + str(l + 1)] = dW_temp\n",
    "        grads[\"db\" + str(l + 1)] = db_temp\n",
    "    return grads"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 5 更新参数\n",
    "def update_parameters(parameters, grads, learning_rate):\n",
    "    \"\"\"\n",
    "    用梯度下降法更新参数\n",
    "    Arguments:\n",
    "    parameters -- 字典，包含参数\n",
    "    grads -- 字典，包含导数，由L_model_backward方法得到\n",
    "    Returns:\n",
    "    parameters --字典，包含更新了的参数\n",
    "                  parameters[\"W\" + str(l)] = ... \n",
    "                  parameters[\"b\" + str(l)] = ...\n",
    "    \"\"\"\n",
    "    L = len(parameters) // 2 # 神经网络的层数\n",
    "    # 更新每一个参数\n",
    "    for l in range(L):\n",
    "        parameters[\"W\" + str(l+1)] -= learning_rate * grads[\"dW\" + str(l+1)]\n",
    "        parameters[\"b\" + str(l+1)] -= learning_rate * grads[\"db\" + str(l+1)]\n",
    "    return parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 6 预测\n",
    "def predict(X, y, parameters):\n",
    "    \"\"\"\n",
    "    Arguments:\n",
    "    X -- 输入数据 \n",
    "    parameters -- 训练好的模型的参数\n",
    "    Returns:\n",
    "    p -- 对给定X的预测\n",
    "    \"\"\"\n",
    "    m = X.shape[1] # 样本数量\n",
    "    n = len(parameters) // 2 # 神经网络的层数\n",
    "    p = np.zeros((1,m))\n",
    "    # 前向传播\n",
    "    probas, caches = L_model_forward(X, parameters)\n",
    "    # 把估计值(0~1之间)转化为0或者1\n",
    "    for i in range(0, probas.shape[1]):\n",
    "        if probas[0,i] > 0.5:  # 因为结果shape是(1,样本数)，是个矩阵，所以不能直接probas[i]\n",
    "            p[0,i] = 1\n",
    "        else:\n",
    "            p[0,i] = 0\n",
    "    print(\"Accuracy: \"  + str(np.sum((p == y)/m)))\n",
    "    return p"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# final：神经网络！\n",
    "def L_layer_model(X, Y, layers_dims, learning_rate = 0.0075, num_iterations = 3000, print_cost=False):#lr was 0.009\n",
    "    \"\"\"\n",
    "    实现一个L层的神经网络: [LINEAR->RELU]*(L-1)->LINEAR->SIGMOID.\n",
    "    Arguments:\n",
    "    X -- 数据，shape为 (样本数, 像素 * 像素 * 3)\n",
    "    Y -- 真实值向量 (是猫：1，不是猫：0),shape为 (1, 样本数)\n",
    "    layers_dims -- 包含每一层的节点数\n",
    "    learning_rate -- 梯度下降更新的速率\n",
    "    num_iterations -- 迭代次数\n",
    "    print_cost -- 如果置为True，每迭代100次就输出一次cost\n",
    "    Returns:\n",
    "    parameters -- 由此模型学习到的参数，可以用它们去做预测\n",
    "    \"\"\"\n",
    "    np.random.seed(1)\n",
    "    costs = []                         # keep track of cost\n",
    "    # 1 参数初始化\n",
    "    parameters = initialize_parameters_deep(layers_dims)\n",
    "    # 梯度下降循环\n",
    "    for i in range(0, num_iterations):\n",
    "        # 2 前向传播: [LINEAR -> RELU]*(L-1) -> LINEAR -> SIGMOID.\n",
    "        AL, caches =  L_model_forward(X, parameters)\n",
    "        # 3 计算cost.\n",
    "        cost = compute_cost(AL, Y)\n",
    "        # 4 后向传播\n",
    "        grads = L_model_backward(AL, Y, caches)\n",
    "        # 5 更新参数\n",
    "        parameters = update_parameters(parameters, grads, learning_rate)\n",
    "        # 每迭代100次就输出一次cost\n",
    "        if print_cost and i % 100 == 0:\n",
    "            print (\"Cost after iteration %i: %f\" %(i, cost))\n",
    "        if print_cost and i % 100 == 0:\n",
    "            costs.append(cost)\n",
    "    # 画出cost曲线\n",
    "    plt.plot(np.squeeze(costs))\n",
    "    plt.ylabel('cost')\n",
    "    plt.xlabel('iterations (per tens)')\n",
    "    plt.title(\"Learning rate =\" + str(learning_rate))\n",
    "    plt.show()\n",
    "    return parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cost after iteration 0: 0.715732\n",
      "Cost after iteration 100: 0.674738\n",
      "Cost after iteration 200: 0.660337\n",
      "Cost after iteration 300: 0.646289\n",
      "Cost after iteration 400: 0.629813\n",
      "Cost after iteration 500: 0.606006\n",
      "Cost after iteration 600: 0.569004\n",
      "Cost after iteration 700: 0.519797\n",
      "Cost after iteration 800: 0.464157\n",
      "Cost after iteration 900: 0.408420\n",
      "Cost after iteration 1000: 0.373155\n",
      "Cost after iteration 1100: 0.305724\n",
      "Cost after iteration 1200: 0.268102\n",
      "Cost after iteration 1300: 0.238725\n",
      "Cost after iteration 1400: 0.206323\n",
      "Cost after iteration 1500: 0.179439\n",
      "Cost after iteration 1600: 0.157987\n",
      "Cost after iteration 1700: 0.142404\n",
      "Cost after iteration 1800: 0.128652\n",
      "Cost after iteration 1900: 0.112443\n",
      "Cost after iteration 2000: 0.085056\n",
      "Cost after iteration 2100: 0.057584\n",
      "Cost after iteration 2200: 0.044568\n",
      "Cost after iteration 2300: 0.038083\n",
      "Cost after iteration 2400: 0.034411\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n4HTOuUr6f/ydTE7hBbBmAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x28e70241908>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 训练参数\n",
    "parameters = L_layer_model(train_x, train_y, layers_dims, num_iterations = 2500, print_cost = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.9952153110047844\n"
     ]
    }
   ],
   "source": [
    "# 去预测训练集\n",
    "pred_train = predict(train_x, train_y, parameters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.78\n"
     ]
    }
   ],
   "source": [
    "# 去预测测试集\n",
    "pred_test = predict(test_x, test_y, parameters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
